package com.zlc.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.zlc.common.common.constant.DataRoleEnum;
import com.zlc.common.common.entity.PageVo;
import com.zlc.common.common.exception.BusinessException;
import com.zlc.common.common.service.AutowiredService;
import com.zlc.common.core.position.model.entity.MayanPlatPosition;
import com.zlc.common.core.position.model.vo.MayanPlatPositionVo;
import com.zlc.common.core.resource.model.entity.MayanPlatResourceRole;
import com.zlc.common.core.resource.model.vo.MayanPlatResourceRoleVo;
import com.zlc.common.core.role.model.entity.MayanPlatDataRoleConfig;
import com.zlc.common.core.role.model.entity.MayanPlatRole;
import com.zlc.common.core.role.model.entity.MayanPlatRoleClass;
import com.zlc.common.core.role.model.entity.MayanPlatRoleUser;
import com.zlc.common.core.role.model.vo.MayanPlatDataRoleConfigVo;
import com.zlc.common.core.role.model.vo.MayanPlatRoleClassVo;
import com.zlc.common.core.role.model.vo.MayanPlatRoleUserVo;
import com.zlc.common.core.role.model.vo.MayanPlatRoleVo;
import com.zlc.common.core.role.service.MayanPlatDataRoleConfigService;
import com.zlc.common.core.user.model.vo.MayanPlatUserVo;
import com.zlc.common.model.resource.ResourceEntity;
import com.zlc.common.model.resource.ResourceRoleVo;
import com.zlc.common.model.role.DataRoleVo;
import com.zlc.common.model.role.RolePageRequest;
import com.zlc.common.model.role.RoleUserPageRequest;
import com.zlc.common.model.role.UserRoleVo;
import com.zlc.common.util.AssertUtils;
import com.zlc.common.util.BeanCopyUtils;
import com.zlc.common.util.PlatUtils;
import com.zlc.platform.model.RoleResourceEntity;
import com.zlc.platform.service.PositionService;
import com.zlc.platform.service.ResourceService;
import com.zlc.platform.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class RoleServiceImpl extends AutowiredService implements RoleService {

    @Autowired
    private ResourceService resourceService;
    @Autowired
    private PositionService positionService;
    @Autowired
    private MayanPlatDataRoleConfigService mayanPlatDataRoleConfigService;

    @Override
    public void addRoleClass(MayanPlatRoleClassVo roleClassVo) {
        String className = roleClassVo.getClassName();
        AssertUtils.isTrue(!ObjectUtils.isEmpty(className),"类别不可为空");
        LambdaQueryWrapper<MayanPlatRoleClass> wrapper = mayanPlatRoleClassService.wrapper()
                .eq(MayanPlatRoleClass::getClassName, className);
        List<MayanPlatRoleClass> list = mayanPlatRoleClassService.list(wrapper);
        AssertUtils.isTrue(ObjectUtils.isEmpty(list),"类别【"+className+"】已存在");
        roleClassVo.setClassId(PlatUtils.uuid());
        mayanPlatRoleClassService.saveVo(roleClassVo);
    }

    @Override
    public void updateRoleClass(MayanPlatRoleClassVo roleClassVo) {
        String id = roleClassVo.getId();
        String className = roleClassVo.getClassName();
        AssertUtils.isTrue(!ObjectUtils.isEmpty(className),"类别不可为空");
        LambdaQueryWrapper<MayanPlatRoleClass> wrapper = mayanPlatRoleClassService.wrapper()
                .eq(MayanPlatRoleClass::getClassName, className);
        MayanPlatRoleClassVo oldRoleClassVo = mayanPlatRoleClassService.queryOne(wrapper);
        if(!ObjectUtils.isEmpty(oldRoleClassVo) && !oldRoleClassVo.getId().equals(id)){
            throw new BusinessException("类别【"+className+"】已存在");
        }
        mayanPlatRoleClassService.saveVo(roleClassVo);
    }

    @Override
    public void deleteRoleClass(String id) {
        MayanPlatRoleClass roleClass = mayanPlatRoleClassService.getById(id);
        LambdaQueryWrapper<MayanPlatRole> wrapper = mayanPlatRoleService.wrapper();
        wrapper.eq(MayanPlatRole::getClassId,roleClass.getClassId());
        List<MayanPlatRoleVo> mayanPlatRoleVos = mayanPlatRoleService.queryVoList(wrapper);
        if(!ObjectUtils.isEmpty(mayanPlatRoleVos)){
            throw new BusinessException("类别下存在未删除的角色，不可删除类别");
        }
        mayanPlatRoleClassService.removeById(id);
    }

    @Override
    public List<MayanPlatRoleClassVo> getList() {
        LambdaQueryWrapper<MayanPlatRoleClass> wrapper = new LambdaQueryWrapper<MayanPlatRoleClass>();
        wrapper.orderByAsc(MayanPlatRoleClass::getCreateTime);
        return mayanPlatRoleClassService.queryVoList(wrapper);
    }

    @Override
    public PageVo<MayanPlatRole> getRoleList(RolePageRequest pageRequest) {
        String classId = pageRequest.getClassId();
        PageHelper.startPage(pageRequest.getPageNum(),pageRequest.getPageSize());
        LambdaQueryWrapper<MayanPlatRole> wrapper = mayanPlatRoleService.wrapper();
        if(!ObjectUtils.isEmpty(classId)) {
            wrapper.eq(MayanPlatRole::getClassId, classId);
        }
        if(!ObjectUtils.isEmpty(pageRequest.getRoleCode())){
            wrapper.and(wr->wr.like(MayanPlatRole::getRoleCode,pageRequest.getRoleCode()).or()
                    .like(MayanPlatRole::getRoleName,pageRequest.getRoleCode()));
        }
        wrapper.orderByDesc(MayanPlatRole::getCreateTime);
        List<MayanPlatRole> mayanPlatRoleVos = mayanPlatRoleService.list(wrapper);
        //查询数据权限
        List<String> roleCodes = mayanPlatRoleVos.stream().map(MayanPlatRole::getRoleCode).collect(Collectors.toList());
        List<MayanPlatDataRoleConfigVo> dataRoleList = mayanPlatDataRoleConfigService.getByRoleCodeList(roleCodes);
        mayanPlatRoleVos.forEach(role->{
            MayanPlatDataRoleConfigVo dataRoleConfig = dataRoleList.stream().filter(dataRole -> dataRole.getRoleCode().equals(role.getRoleCode())).findFirst().orElse(null);
            if(!ObjectUtils.isEmpty(dataRoleConfig)){
                role.setDataRoleType(dataRoleConfig.getType());
                role.setDataRole(dataRoleConfig);
            }
        });
        return PageVo.page(mayanPlatRoleVos);
    }



    @Override
    public void addRole(MayanPlatRoleVo roleVo) {
        String classId = roleVo.getClassId();
        AssertUtils.isTrue(!ObjectUtils.isEmpty(classId),"所属类别不可为空");
        String roleCode = roleVo.getRoleCode();
        LambdaQueryWrapper<MayanPlatRole> wrapper = mayanPlatRoleService.wrapper()
                .eq(MayanPlatRole::getRoleCode, roleCode);
        MayanPlatRoleVo oldRoleVo = mayanPlatRoleService.queryOne(wrapper);
        AssertUtils.isTrue(ObjectUtils.isEmpty(oldRoleVo),"roleCode【"+roleCode+"】已存在");
        mayanPlatRoleService.saveVo(roleVo);
    }

    @Override
    public void updateRole(MayanPlatRoleVo roleVo) {
        String classId = roleVo.getClassId();
        AssertUtils.isTrue(!ObjectUtils.isEmpty(classId),"所属类别不可为空");
        String roleCode = roleVo.getRoleCode();
        LambdaQueryWrapper<MayanPlatRole> wrapper = mayanPlatRoleService.wrapper()
                .eq(MayanPlatRole::getRoleCode, roleCode);
        MayanPlatRoleVo oldRoleVo = mayanPlatRoleService.queryOne(wrapper);
        if(!ObjectUtils.isEmpty(oldRoleVo) && !oldRoleVo.getId().equals(roleVo.getId())){
            throw new BusinessException("roleCode【"+roleCode+"】已存在");
        }
        mayanPlatRoleService.saveVo(roleVo);
    }

    @Override
    public void removeRole(String id) {
        MayanPlatRole role = mayanPlatRoleService.getById(id);
        mayanPlatRoleService.removeById(id);
        if(!ObjectUtils.isEmpty(role) && !ObjectUtils.isEmpty(role.getRoleCode())){
            mayanPlatResourceRoleMapper.deleteByRoleCode(role.getRoleCode());
            mayanPlatRoleUserMapper.deleteByRoleCode(role.getRoleCode());

            LambdaQueryWrapper<MayanPlatPosition> wrapper = mayanPlatPositionService.wrapper();
            wrapper.eq(MayanPlatPosition::getRoleCode,role.getRoleCode());
            List<MayanPlatPositionVo> mayanPlatPositionVos = mayanPlatPositionService.queryVoList(wrapper);
            mayanPlatPositionMapper.deleteByRoleCode(role.getRoleCode());
            if(!ObjectUtils.isEmpty(mayanPlatPositionVos)){
                List<String> positionCodes = mayanPlatPositionVos.stream().map(MayanPlatPositionVo::getPositionCode).collect(Collectors.toList());
                mayanPlatPositionUserMapper.deleteByPositionCodes(positionCodes);
            }
        }
    }

    @Override
    public PageVo<MayanPlatUserVo> getUserListByRoleCode(RoleUserPageRequest pageRequest) {
        String roleCode = pageRequest.getRoleCode();
        String username = pageRequest.getUsername();
        PageHelper.startPage(pageRequest.getPageNum(),pageRequest.getPageSize());
        List<MayanPlatUserVo> mayanPlatUserVos = mayanPlatRoleUserMapper.queryRoleUserList(roleCode,username);
        return PageVo.page(mayanPlatUserVos);
    }

    @Override
    public List<UserRoleVo> getRoleByAccount(String account) {
        LambdaQueryWrapper<MayanPlatRoleUser> wrapper = mayanPlatRoleUserService.wrapper();
        wrapper.eq(MayanPlatRoleUser::getUserAccount,account);
        List<MayanPlatRoleUserVo> mayanPlatRoleUserVos = mayanPlatRoleUserService.queryVoList(wrapper);
        if(!ObjectUtils.isEmpty(mayanPlatRoleUserVos)){
            List<String> roleCodes = mayanPlatRoleUserVos.stream().map(MayanPlatRoleUserVo::getRoleCode).collect(Collectors.toList());
            LambdaQueryWrapper<MayanPlatRole> roleWrapper = mayanPlatRoleService.wrapper();
            roleWrapper.in(MayanPlatRole::getRoleCode,roleCodes);
            List<MayanPlatRoleVo> mayanPlatRoleVos = mayanPlatRoleService.queryVoList(roleWrapper);
            if(!ObjectUtils.isEmpty(mayanPlatRoleVos)){
                return mayanPlatRoleVos.stream().flatMap(f->{
                    UserRoleVo roleVo = new UserRoleVo();
                    roleVo.setRoleCode(f.getRoleCode());
                    roleVo.setRoleName(f.getRoleName());
                    return Stream.of(roleVo);
                }).collect(Collectors.toList());
            }
        }
        return new ArrayList<>();
    }

    @Override
    public void relateUser(MayanPlatRoleUserVo userVo) {
        String roleCode = userVo.getRoleCode();
        String userAccount = userVo.getUserAccount();
        AssertUtils.isTrue(!ObjectUtils.isEmpty(roleCode),"所属角色不可为空");
        AssertUtils.isTrue(!ObjectUtils.isEmpty(userAccount),"员工不可为空");
        LambdaQueryWrapper<MayanPlatRoleUser> wrapper = mayanPlatRoleUserService.wrapper()
                .eq(MayanPlatRoleUser::getRoleCode, roleCode)
                .eq(MayanPlatRoleUser::getUserAccount,userAccount);
        MayanPlatRoleUserVo oldRoleUserVo = mayanPlatRoleUserService.queryOne(wrapper);
        AssertUtils.isTrue(ObjectUtils.isEmpty(oldRoleUserVo),"用户【"+userAccount+"】已关联");
        mayanPlatRoleUserService.saveVo(userVo);
    }

    @Override
    public void relateUserList(List<MayanPlatRoleUserVo> userVos) {
        for(MayanPlatRoleUserVo userVo : userVos){
            relateUser(userVo);
        }
    }

    @Override
    public void removeRelateUser(String relateId) {
        mayanPlatRoleUserService.removeById(relateId);
    }

    @Override
    public void removeRelateUserList(List<String> relateIdList) {
        mayanPlatRoleUserService.removeByIds(relateIdList);
    }

    @Override
    public RoleResourceEntity queryRelateResource(String roleCode) {
        RoleResourceEntity result = new RoleResourceEntity();
        //所有资源
        List<ResourceEntity> entities = resourceService.queryAllResource();
        result.setResources(entities);
        //所有选中的资源
        LambdaQueryWrapper<MayanPlatResourceRole> wrapper = mayanPlatResourceRoleService.wrapper();
        wrapper.eq(MayanPlatResourceRole::getRoleCode,roleCode);
        List<MayanPlatResourceRoleVo> resourceRoleVos = mayanPlatResourceRoleService.queryVoList(wrapper);
        //选中的资源id
        List<String> checkedList = new ArrayList<>();
        if(!ObjectUtils.isEmpty(resourceRoleVos)){
            checkedList = resourceRoleVos.stream().map(MayanPlatResourceRoleVo::getResourceId).collect(Collectors.toList());
        }
        if(ObjectUtils.isEmpty(checkedList)){
            return result;
        }
        result.setCheckedList(checkedList);
        for(ResourceEntity entity : entities){
            loadResourceChecked(entity,checkedList);
        }
        return result;
    }


    private void loadResourceChecked(ResourceEntity entity,List<String> checkedList){
        if(entity.getResourceId() != null && checkedList.contains(entity.getResourceId())){
            entity.setCheckType("CHECK");
        }else{
            entity.setCheckType("NO");
        }
        List<ResourceEntity> children = entity.getChildren();
        for(ResourceEntity child : children){
            loadResourceChecked(child,checkedList);
        }
        if(!ObjectUtils.isEmpty(children)){
            List<ResourceEntity> checkList = children.stream().filter(c -> "CHECK".equals(c.getCheckType())).collect(Collectors.toList());
            if(!ObjectUtils.isEmpty(checkList)){
                entity.setCheckType("PART");
            }
            if(children.size() == checkList.size()){
                entity.setCheckType("CHECK");
            }
        }
    }

    @Override
    public void relateResource(ResourceRoleVo resourceRoleVo) {
        //校验
        String roleCode = resourceRoleVo.getRoleCode();
        AssertUtils.isTrue(!ObjectUtils.isEmpty(roleCode),"角色code不可为空");
        MayanPlatRoleVo roleVo = mayanPlatRoleService.getByRoleCode(roleCode);
        AssertUtils.isTrue(!ObjectUtils.isEmpty(roleVo),"角色不存在");
        //删除现有的关联资源
        mayanPlatResourceRoleMapper.deleteByRoleCode(roleCode);
        //重新保存关联资源
        List<String> resourceIds = resourceRoleVo.getResourceIds();
        if(!ObjectUtils.isEmpty(resourceIds)){
            for(String resourceId : resourceIds){
                MayanPlatResourceRoleVo rrv = new MayanPlatResourceRoleVo();
                rrv.setRoleCode(roleCode);
                rrv.setResourceId(resourceId);
                mayanPlatResourceRoleService.saveVo(rrv);
            }
        }
    }

    @Override
    public void saveRoleDataConfig(MayanPlatDataRoleConfigVo roleConfigVo) {
        String roleCode = roleConfigVo.getRoleCode();
        AssertUtils.isTrue(!ObjectUtils.isEmpty(roleCode),"所属角色不可为空");
        List<MayanPlatDataRoleConfigVo> roleConfigVos = mayanPlatDataRoleConfigService.getByRoleCodeList(Collections.singletonList(roleCode));
        if(!ObjectUtils.isEmpty(roleConfigVos)){
            MayanPlatDataRoleConfigVo roleConfig = roleConfigVos.get(0);
            roleConfig.setType(roleConfigVo.getType());
            roleConfig.setCustomDeptCode(roleConfigVo.getCustomDeptCode());
            mayanPlatDataRoleConfigService.saveVo(roleConfig);
            return;
        }
        mayanPlatDataRoleConfigService.saveVo(roleConfigVo);
    }

    @Override
    public MayanPlatDataRoleConfigVo queryDataRoleConfig(String roleCode) {
        AssertUtils.isTrue(!ObjectUtils.isEmpty(roleCode),"所属角色不可为空");
        MayanPlatRoleVo roleVo = mayanPlatRoleService.getByRoleCode(roleCode);
        AssertUtils.isTrue(!ObjectUtils.isEmpty(roleVo),"所属角色不存在");
        LambdaQueryWrapper<MayanPlatDataRoleConfig> wrapper = mayanPlatDataRoleConfigService.wrapper();
        wrapper.eq(MayanPlatDataRoleConfig::getRoleCode,roleCode);
        MayanPlatDataRoleConfigVo mayanPlatDataRoleConfigVo = mayanPlatDataRoleConfigService.queryOne(wrapper);
        if(ObjectUtils.isEmpty(mayanPlatDataRoleConfigVo)){
            mayanPlatDataRoleConfigVo = new MayanPlatDataRoleConfigVo();
            mayanPlatDataRoleConfigVo.setRoleCode(roleCode);
            return mayanPlatDataRoleConfigVo;
        }
        return mayanPlatDataRoleConfigVo;
    }

    @Override
    public DataRoleVo queryDataRoleByAccount(List<String> roleCodes) {
        DataRoleVo result = new DataRoleVo();
        LambdaQueryWrapper<MayanPlatDataRoleConfig> wrapper = mayanPlatDataRoleConfigService.wrapper();
        wrapper.in(MayanPlatDataRoleConfig::getRoleCode,roleCodes);
        List<MayanPlatDataRoleConfigVo> dataRoleConfigVos = mayanPlatDataRoleConfigService.queryVoList(wrapper);
        if(ObjectUtils.isEmpty(dataRoleConfigVos)){
            //默认查询自己
            result.setType(DataRoleEnum.SELF.getType());
            return result;
        }
        MayanPlatDataRoleConfigVo allConfig = dataRoleConfigVos.stream().filter(d -> DataRoleEnum.ALL.getType().equals(d.getType())).findFirst().orElse(null);
        if(!ObjectUtils.isEmpty(allConfig)){
            result.setType(DataRoleEnum.ALL.getType());
            return result;
        }
        MayanPlatDataRoleConfigVo customConfig = dataRoleConfigVos.stream().filter(d -> DataRoleEnum.CUSTOM.getType().equals(d.getType())).findFirst().orElse(null);
        if(!ObjectUtils.isEmpty(customConfig)){
            result.setType(DataRoleEnum.CUSTOM.getType());
            String customDeptCode = customConfig.getCustomDeptCode();
            if(!ObjectUtils.isEmpty(customDeptCode)){
                List<String> deptCodes = new ArrayList<>(Arrays.asList(StringUtils.split(customDeptCode,",")));
                result.setCustomDeptCodes(deptCodes);
            }
            return result;
        }
        MayanPlatDataRoleConfigVo deptConfig = dataRoleConfigVos.stream().filter(d -> DataRoleEnum.DEPT.getType().equals(d.getType())).findFirst().orElse(null);
        if(!ObjectUtils.isEmpty(deptConfig)){
            result.setType(DataRoleEnum.DEPT.getType());
            return result;
        }
        result.setType(DataRoleEnum.SELF.getType());
        return result;
    }
}
